﻿using System;
using System.Collections;
using System.Data;
using MySql.Data.MySqlClient;

public abstract class SuperT : ObjetoT
{
    #region Atributos

    /// \brief Nombre del atributo de la BD que identifica de forma unívoca la actividad.
    internal string cId = "ID";

    protected MySqlDataAdapter adaptador;
    protected DataTable miTabla;

    #endregion

    #region Constructores

    /**
    * \brief Constructor de la clase SuperT.
    * \pre El valor del objeto nombreTabla no puede ser nulo.
    * \return El objeto SuperT inicializado y listo para ser usado.
    * \param pLogActivo - Permiso para usar el Log.
    * \param pNombreTabla - Nombre de la tabla en la BBDD.
    */
    public SuperT(MySqlConnection pConexion, string pNombreTabla) : base(pNombreTabla)
    {
        try
        {
            this.conexion = pConexion;
            this.miTabla = new DataTable(pNombreTabla);              

        }
        catch (Exception)
        {
            throw new Exception("Error: Constructor clase SuperT; " + this.NombreTabla);
        }
    }

    #endregion

    #region Métodos de Gestión de Tablas

    protected abstract ColEncapsulados consultarDataTable(DataRowCollection pFilas);

    protected abstract void insertar(ColEncapsulados pColeccion);
    protected abstract void modificar(ColEncapsulados pColeccion);
    protected abstract void eliminar(ColEncapsulados pColeccion);

    #endregion

    #region Métodos de Gestión de Datos

    /**
    * \brief Rellena el DataTable a partir de la sentencia pasada por argumento.
    * \pre La sentencia SQL debe de ser correcta
    * \param pSQL - Cadena de Texto con la sentencia SQL de actualización.
    * \param pTipoDeAccion - Tipo de Accion que se está ejecutando
    */
    internal DataTable rellenarDataTable(string pSQL, EnumTiposDeAccion pTipoDeAccion)
    {
        try
        {
            DataTable tablaConsulta = this.miTabla;

            //Si estamos consultando en una tabla que no es de aplicacion, hay que crear una nueva tabla
            if(pTipoDeAccion == EnumTiposDeAccion.Consultar)
            {
                tablaConsulta = new DataTable(this.nombreTabla);
                        
                this.inicializarAdaptador(pSQL);
                this.inicializarTabla(tablaConsulta);
            }
            //Si estamos realizando cualquier otra accion, tenemos que devolver la tabla de la aplicacion
            else
            {
                if (this.adaptador == null)
                    this.inicializarAdaptador(pSQL);
                else
                    this.inicializarComandoDelAdaptador(pSQL);

                this.inicializarTabla(tablaConsulta);
            }
                
            return tablaConsulta;
                
        }
        catch (Exception)
        {
            throw new Exception("Error: Metodo rellenarDataTable; Clase SuperT; Sentencia: " + pSQL);
        }
    }

    /**
    * \brief Metodo encargado de actualizar las modificaciones realizadas sobre miTabla en la BBDD
    * \return El numero de modificaciones. Si se devuelve -1 es que ha habido algún error
    * \param pTransaccion - Transaccion bajo la cual se actualiza
    */
    protected virtual int actualizar(MySqlTransaction pTransaccion)
    {
        try
        {
            if (this.adaptador == null)
                inicializarAdaptador("");
            this.adaptador.SelectCommand.Transaction = pTransaccion;
            return this.ejecutarUpdate(pTransaccion);

        }
        catch (MySqlException e)
        {
            throw e;
        }
        catch (Exception)
        {
            throw new Exception("Error: metodo actualizar; clase SuperT;" + this.NombreTabla);
        }
    }
    /**
    * \brief Realiza una consulta escalar sobre la base de datos
    * \pre el filtro debe de ser correcto. Para ello, solo tiene que tener las condiciones de filtrado
    * \exception SGIException se lanzara si ocurre algun error al realizar la consulta
    * \return itn Numero de filas
    * \param sentencia Cadena de Texto con el filtro a aplicar
    */
    public virtual int consultarNumeroFilas(String pFiltro)
    {
        try
        {
            int resultado = -1;
            string sql = "SELECT count(*) FROM " + this.nombreTabla + " WHERE " + pFiltro;

            IDbCommand comando = this.crearComando(sql);

            this.conexion.Open();
            resultado = System.Convert.ToInt16(comando.ExecuteScalar());
            this.conexion.Close();

            return resultado;
        }
        catch (Exception)
        {
            this.conexion.Close();
            throw new Exception("Error: metodo consultarNumeroFilas; clase SuperT");
        }
    }

    /**
    * \brief Metodo encargado de actualizar las modificaciones realizadas sobre miTabla en la BBDD
    * \return El numero de modificaciones. Si se devuelve -1 es que ha habido algún error
    * \param pTransaccion - Transaccion bajo la cual se actualiza
    */
    internal virtual int confirmarCambiosBBDD(MySqlTransaction pTransaccion)
    {
        return this.actualizar(pTransaccion);
    }
    /**
    * \brief Metodo encargado de actualizar las modificaciones realizadas sobre miTabla en la BBDD
    * \return El numero de modificaciones. Si se devuelve -1 es que ha habido algún error
    * \param pTransaccion - Transaccion bajo la cual se actualiza
    */
    internal virtual void confirmarCambiosDataTable()
    {
        this.miTabla.AcceptChanges();
    }
    /**
    * \brief Metodo encargado de deshacer las modificaciones realizadas sobre miTabla en la BBDD
    */
    public virtual void deshacerCambios()
    {
        this.miTabla.RejectChanges();
    }

    protected string getSQLTabla()
    {
        string sql = "SELECT * FROM " + this.nombreTabla;
        return sql;
    }
    protected string getSQLTablaVacia()
    {
        string sql = "SELECT * FROM " + this.nombreTabla + " WHERE 0=1";
        return sql;
    }

    #endregion

    #region Metodos internos

    protected void inicializarAdaptador(string pSQL)
    {
        if (this.conexion is MySqlConnection)
        {              
            this.adaptador = new MySqlDataAdapter(pSQL, (MySqlConnection)this.conexion);                
        }

    }
    protected void inicializarTabla(DataTable pTablaConsulta)
    {
        if (this.adaptador is MySqlDataAdapter)
        {
            this.adaptador.MissingSchemaAction = MissingSchemaAction.AddWithKey;
            ((MySqlDataAdapter)this.adaptador).Fill(pTablaConsulta);
        }
    }
    protected void inicializarComandoDelAdaptador(string pSQL)
    {
        if (this.adaptador is MySqlDataAdapter)
        {
            ((MySqlDataAdapter)this.adaptador).SelectCommand = new MySqlCommand(pSQL, (MySqlConnection)this.conexion);
        }
    }
    protected int ejecutarUpdate(MySqlTransaction pTransaccion)
    {
        if (this.adaptador is MySqlDataAdapter)
        {
            MySqlCommandBuilder comando = new MySqlCommandBuilder((MySqlDataAdapter)adaptador);
            adaptador.InsertCommand = (MySqlCommand)comando.GetInsertCommand();
            adaptador.UpdateCommand = (MySqlCommand)comando.GetUpdateCommand();
            adaptador.DeleteCommand = (MySqlCommand)comando.GetDeleteCommand();
            adaptador.InsertCommand.Transaction = pTransaccion;
            adaptador.UpdateCommand.Transaction = pTransaccion;
            adaptador.DeleteCommand.Transaction = pTransaccion;

            return ((MySqlDataAdapter)this.adaptador).Update(this.miTabla); 
        }
        else
            return -1;
    }

    #endregion
        
}